package com.byjh.common.utils;

import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import javax.naming.AuthenticationException;
import java.io.IOException;
import java.util.*;

import static com.byjh.common.constant.WechatConstants.*;

/**
 * 微信工具类
 */
public class WechatUtils {

    // API错误码常量
    private static final int SUCCESS_ERR_CODE = 0;

    /**
     * 小程序token
     *
     * @param appId
     * @param secret
     * @return
     */
    public static String token(String appId, String secret) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("grant_type", "client_credential");
        params.put("appid", appId);
        params.put("secret", secret);
        JSONObject json = (JSONObject) JSONUtil.parse(HttpUtil.get(TOKEN_URL, params));
        if (StringUtils.isEmpty(json.getStr("access_token"))) {
            return "";
        }
        return json.getStr("access_token");
    }

    /**
     * 获取小程序openid
     */
    public static String getOpenId(String code, String appId, String secret) throws AuthenticationException {
        if (code == null || code.isEmpty()) {
            throw new IllegalArgumentException("Code cannot be null or empty.");
        }
        Map<String, Object> requestParameters = new HashMap<>();
        requestParameters.put(APPID_KEY, appId);
        requestParameters.put(SECRET_KEY, secret);
        requestParameters.put(JS_CODE_KEY, code);
        requestParameters.put(GRANT_TYPE_KEY, AUTHORIZATION_CODE);
        try {
            String res = HttpUtil.post(AUTHORIZE_CODE_URL, requestParameters);
            JSONObject result = JSONUtil.parseObj(res);
            if (!result.isEmpty() && result.containsKey(OPENID_KEY)) {
                return result.getStr(OPENID_KEY);
            }
            throw new AuthenticationException("Empty or null response received while fetching openId.");
        } catch (Exception e) {
            throw new AuthenticationException("Exception occurred while fetching openId: " + e.getMessage());
        }
    }

    /**
     * 微信获取手机号码
     *
     * @param code  验证码
     * @param token 安全令牌
     * @return 手机号码
     * @throws AuthenticationException 验证失败时抛出异常
     * @throws IOException             网络请求异常
     */
    public static String authenticatePhoneNumber(String code, String token) throws AuthenticationException, IOException {
        validateParams(code, token);
        try {
            // 发送请求获取响应
            JSONObject response = sendAuthenticationRequest(code, token);
            // 验证响应
            validateResponse(response);
            // 提取手机号码
            return extractPhoneNumber(response);
        } catch (RestClientException e) {
            throw new AuthenticationException("认证服务请求失败");
        }
    }


    private static void validateParams(String code, String token) {
        if (StringUtils.isBlank(code) || StringUtils.isBlank(token)) {
            throw new IllegalArgumentException("验证码和令牌不能为空");
        }
    }

    private static JSONObject sendAuthenticationRequest(String code, String token) {
        Map<String, String> params = Collections.singletonMap("code", code);
        // 执行HTTP POST请求
        ResponseEntity<JSONObject> result = new RestTemplate().postForEntity(String.format(PHONE_URL, token), params, JSONObject.class);
        return result.getBody();
    }

    private static void validateResponse(JSONObject response) throws AuthenticationException {
        if (response == null) {
            throw new AuthenticationException("服务器响应为空");
        }
        int errCode = response.getInt("errcode");
        String errMsg = response.getStr("errmsg");
        if (errCode != SUCCESS_ERR_CODE) {
            throw new AuthenticationException("认证失败: " + errMsg);
        }
    }

    private static String extractPhoneNumber(JSONObject response) throws AuthenticationException {
        JSONObject phoneInfo = response.getJSONObject("phone_info");
        if (phoneInfo == null) {
            throw new AuthenticationException("响应中未包含手机号信息");
        }
        String phoneNumber = phoneInfo.getStr("phoneNumber");
        if (StringUtils.isBlank(phoneNumber)) {
            throw new AuthenticationException("获取到的手机号为空");
        }
        return phoneNumber;
    }

}
